// Copyright 2015 Eivind Vegsundvåg
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ninja.eivind.hotsreplayuploader.utils;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
/**
* Helper class for JavaFX related problems.
*/
public final class FXUtils {
private FXUtils() {
}
public static <T> void autoCompleteComboBox(ComboBox<T> comboBox, AutoCompleteMode mode) {
final ObservableList<T> data = comboBox.getItems();
comboBox.setEditable(true);
comboBox.getEditor().focusedProperty().addListener(observable -> {
if (0 > comboBox.getSelectionModel().getSelectedIndex()) {
comboBox.getEditor().setText(null);
}
});
comboBox.addEventHandler(KeyEvent.KEY_PRESSED, t -> comboBox.hide());
comboBox.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
private boolean moveCaretToPos = false;
private int caretPos;
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case DOWN:
if (!comboBox.isShowing()) {
comboBox.show();
}
case UP:
caretPos = -1;
moveCaret(comboBox.getEditor().getText().length());
return;
case BACK_SPACE:
case DELETE:
moveCaretToPos = true;
caretPos = comboBox.getEditor().getCaretPosition();
break;
}
if (KeyCode.RIGHT == event.getCode() || KeyCode.LEFT == event.getCode()
|| event.isControlDown() || KeyCode.HOME == event.getCode()
|| KeyCode.END == event.getCode() || KeyCode.TAB == event.getCode()) {
return;
}
final ObservableList<T> list = FXCollections.observableArrayList();
for (T aData : data) {
if (shouldDataBeAddedToInput(aData)) {
list.add(aData);
}
}
final String text = comboBox.getEditor().getText();
comboBox.setItems(list);
comboBox.getEditor().setText(text);
if (!moveCaretToPos) {
caretPos = -1;
}
moveCaret(text.length());
if (!list.isEmpty()) {
comboBox.show();
}
}
private boolean shouldDataBeAddedToInput(T aData) {
return mode.equals(AutoCompleteMode.STARTS_WITH) && inputStartsWith(aData)
|| mode.equals(AutoCompleteMode.CONTAINING) && inputContains(aData);
}
private boolean inputStartsWith(T aData) {
final String dataValue = aData.toString().toLowerCase();
final String inputValue = comboBox.getEditor().getText().toLowerCase();
return dataValue.startsWith(inputValue);
}
private boolean inputContains(T aData) {
final String dataValue = aData.toString().toLowerCase();
final String inputValue = comboBox.getEditor().getText().toLowerCase();
return dataValue.contains(inputValue);
}
private void moveCaret(int textLength) {
if (-1 == caretPos) {
comboBox.getEditor().positionCaret(textLength);
} else {
comboBox.getEditor().positionCaret(caretPos);
}
moveCaretToPos = false;
}
});
}
public enum AutoCompleteMode {
STARTS_WITH, CONTAINING,;
}
}